1. img标签之object-fit属性
很简单的需求,一个上传图片的按钮,上传完毕之后把图片展示到按钮里,完成之后,我考虑到用户如果上传的图片太小或者太大,会影响视觉效果,果然在旁边做了个预览功能,方便用户放大看图,做完直接,提交代码。没多久测试提了个bug,上传的图片会拉伸,希望图片做到高保真,我一想,肯定会拉伸啊,旁边既然都有预览功能了,其实无所谓的,如图:
然后我就在思考,我要怎么在保持图片宽高比例不变的情况下,还能撑满整个按钮,没多久,我就做了个骚操作,如下
当时我都觉得完美,提交上去之后,谁都没发现问题。如下,问题一下就暴露出来了,我不去限制高度,然后宽度自适应,最后居中,完美地做了个伪高保真,后来我一想不对啊,这种内容都在中间的图片没问题,一旦图片的内容都在左侧,岂不是凉了?
后来通过研究antd上传组件,发现了object-fit这个属性,果然css还是有很多的属性不太被经常使用,所以会被忽略,平时还需要多积累积累。
object-fit:指定元素的内容应该如何去适应指定容器的高度与宽度,一般用于 img 和 video 标签,一般可以对这些元素进行保留原始比例的剪切、缩放或者直接进行拉伸等。
值 |
描述 |
fill |
默认,不保证保持原有的比例,内容拉伸填充整个内容容器。 |
contain |
保持原有尺寸比例。内容被缩放。 |
none |
保留原有元素内容的长度和宽度,也就是说内容不会被重置 |
scale-down |
保持原有尺寸比例。内容的尺寸与 none 或 contain 中的一个相同,取决于它们两个之间谁得到的对象尺寸会更小一些。 |
initial |
设置为默认值,关于 initial |
inherit |
从该元素的父元素继承属性 |
1 2 3 4 5 6
| // 最后修改代码 .ym_upload-img-list-item { width: 100%; height: 100%; object-fit: contain; }
|
实现效果如下,这次才是真正的完美:
2. 组件中,错误事件的传递
最近我们在开发公司自用的组件库,其实就是基于antd根据公司的业务做一层封装。
在我写的一个组件,有这样一个警告,大致就是handleChange事件并不在元素上存在
一开始我也没看出问题出在哪
1 2 3 4
| // 父组件 <AreaSelect handleChange={handleChange} />
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| // 子组件 import RequestHelper from "@/utils/request"; import React, { useCallback, useEffect, useState } from "react"; import { Cascader } from 'antd'; import "./index.less";
const request = new RequestHelper("").jsonRequest();
interface IProps { level?: string; className?: string; fieldNamesOptions?: {}; handleChange?: (value: [], selectedOptions: []) => void; }
export const AreaSelect: React.FC<IProps> = (props: any) => { const { handleChange, level, fieldNamesOptions, className, } = props; const [areaData, setAreaData] = useState(); const [fieldNames] = useState(fieldNamesOptions || { label: "name", value: "code", children: "children" }); const getAreaData = useCallback(() => { try { request.get('/public/other/areacode', { level }).then((res) => { const data = res?.data?.data ? res.data.data : []; setAreaData(data); }) } catch (e) { console.log(e); } }, []);
useEffect(() => { getAreaData(); }, []);
const onChange = useCallback((value: [], selectedOptions: []) => { handleChange && handleChange(value, selectedOptions); }, [handleChange]);
return ( <> <Cascader placeholder="请选择" fieldNames={fieldNames} options={areaData} onChange={onChange} {...props} className={`ym_cascader ${className}`} /> </> ) } AreaSelect.defaultProps = { level: "area", } export default AreaSelect;
|
后来经过仔细观察得到答案,问题出在我在给级联组件传递参数的时候,直接用了扩展运算符,把不属于Cascader组件的handleChange也传了过去。。。所以这里我们需要用…rest来接收属于Cascader组件的参数,把不属于他的参数过滤出来。
1 2 3 4 5 6 7 8 9 10 11 12
| const { handleChange, level, fieldNamesOptions, className, ...rest } = props; ... <> <Cascader placeholder="请选择" fieldNames={fieldNames} options={areaData} onChange={onChange} {...rest} className={`ym_cascader ${className}`} /> </>
|
这里还有个需要注意的地方,就是我自定义了一个className,然后还支持传入className,如果我把他写在{…rest}前面,会被rest解构出来的className覆盖掉的,所以要⚠️一个顺序问题。
我的微信公众号: 梨的前端小屋